package nl.avans.osgi.ds.persistence.data.setup;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;

import nl.avans.osgi.ds.persistence.person.model.Address;
import nl.avans.osgi.ds.persistence.person.model.Employee;

import org.eclipse.persistence.config.PersistenceUnitProperties;
import org.eclipse.persistence.jpa.osgi.PersistenceProvider;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;

public class CreateDatabaseService implements BundleActivator{

    public void start(BundleContext context) throws Exception {
        System.out.println("CreateDatabaseService#start");
        EntityManagerFactory emf = null;
        EntityManager em = null;
        try {
            ClassLoader cl = this.getClass().getClassLoader();
            Map<String, Object> properties = new HashMap<String, Object>();
            properties.put("eclipselink.ddl-generation", "drop-and-create-tables");
            properties.put("eclipselink.ddl-generation.output-mode", "database");
            properties.put(PersistenceUnitProperties.CLASSLOADER, cl);
            emf = new PersistenceProvider()
                    .createEntityManagerFactory("persons", properties);
            em = emf.createEntityManager();
            em.getTransaction().begin();

            URL addressFileURL = context.getBundle().getResource("address.tab");
            Map<Long, Address> addresses = loadAddresses(addressFileURL);
            persist(em, addresses.values());

            URL employeeFileURL = context.getBundle().getResource("employee.tab");
            Map<Long, Employee> employees = loadEmployees(employeeFileURL, addresses);
            persist(em, employees.values());
            
            em.getTransaction().commit();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (em != null) {
                em.close();
            }
            if (emf != null) {
                emf.close();
            }
        }
    }
    
    public void stop(BundleContext context) throws Exception {
    }

    private static void persist(EntityManager em, Collection<?> values) {
        for (Object object : values) {
            em.persist(object);
        }
    }

    private Map<Long, Address> loadAddresses(URL addressFileURL) throws IOException {
        Map<Long, Address> addressMapping = new HashMap<Long, Address>();
        BufferedReader reader = null;
        try {
            reader = new BufferedReader(new InputStreamReader(addressFileURL.openStream()));
            String line = null;
            while ((line = reader.readLine()) != null) {
                Address address = createAddress(line);
                addressMapping.put(address.getId(), address);
            }
        } finally {
            if (reader != null) {
                reader.close();
            }
        }
        return addressMapping;
    }

    private Address createAddress(String line) {
        // id, street, number, postalcode, city, country.
        Address address = null;
        String[] data = line.split(";");
        assert data.length == 6;
        long id = Long.parseLong(data[0]);
        address = new Address(id, data[1], data[2], data[3], data[4], data[5]);
        return address;
    }

    private Map<Long, Employee> loadEmployees(URL employeeFileURL, Map<Long, Address> addresses) throws IOException {
        Map<Long, Employee> employeeMapping = new HashMap<Long, Employee>();
        BufferedReader reader = null;
        try {
            reader = new BufferedReader(new InputStreamReader(employeeFileURL.openStream()));
            String line = null;
            while ((line = reader.readLine()) != null) {
                Employee employee = createEmployee(line, addresses);
                employeeMapping.put(employee.getId(), employee);
            }
        } finally {
            if (reader != null) {
                reader.close();
            }
        }
        return employeeMapping;
    }

    private Employee createEmployee(String line, Map<Long, Address> addresses) {
        // id, firstname, lastname, gender, address_id
        Employee person = null;
        String[] data = line.split(";");
        assert data.length == 5;
        long id = Long.parseLong(data[0]);
        Long addressId = Long.decode(data[4]);
        Address address = addresses.get(addressId);
        person = new Employee(id, data[1], data[2], data[3].charAt(0), address);
        return person;
    }

}
